home *** CD-ROM | disk | FTP | other *** search
/ Aminet 43 / Aminet 43 (2001)(GTI - Schatztruhe)[!][Jun 2001].iso / Aminet / comm / tcp / Amster-source.lha / Amster_Install / Source / transfer.c < prev    next >
C/C++ Source or Header  |  2001-03-14  |  14KB  |  550 lines

  1. /*
  2. ** Amster - Transfer
  3. ** Copyright © 1999-2000 by Gürer Özen
  4. ** Copyright © 2000-2001 by Jacob Laursen
  5. **
  6. ** This program is free software; you can redistribute it and/or modify
  7. ** it under the terms of the GNU General Public License as published by
  8. ** the Free Software Foundation; either version 2 of the License, or
  9. ** (at your option) any later version.
  10. **
  11. ** This program is distributed in the hope that it will be useful,
  12. ** but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14. ** GNU General Public License for more details.
  15. **
  16. ** You should have received a copy of the GNU General Public License
  17. ** along with this program; if not, write to the Free Software
  18. ** Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
  19. */
  20.  
  21. #include "amster.h"
  22.  
  23. #include <proto/dos.h>
  24.  
  25. #include <MUI/NListview_mcc.h>
  26.  
  27. #include "network.h"
  28. #include "amster_Cat.h"
  29.  
  30.  
  31. MUI_LIST_DISP(translistdisp, songtrans sd)
  32. {
  33.     static char bufd2[50], bufd3[50], bufd4[50], bufd5[50];
  34.     static char bufu2[50], bufu3[50], bufu4[50], bufu5[50];
  35.     char *buf2, *buf3, *buf4, *buf5;
  36.  
  37.     static char *states[] = {
  38.         (char *)_MSG_TRANS_STAT_PREPARE,
  39.         (char *)_MSG_TRANS_STAT_QUEUE,
  40.         (char *)_MSG_TRANS_STAT_WAIT,
  41.         (char *)_MSG_TRANS_STAT_CONN,
  42.         (char *)_MSG_TRANS_STAT_REQ,
  43.         (char *)_MSG_TRANS_STAT_INIT,
  44.         (char *)_MSG_TRANS_STAT_DL,
  45.         (char *)_MSG_TRANS_STAT_UL,
  46.         (char *)_MSG_TRANS_STAT_FIN,
  47.         (char *)_MSG_TRANS_STAT_ABORT,
  48.         (char *)_MSG_TRANS_STAT_ERROR,
  49.         NULL
  50.     };
  51.  
  52.     static char *errors[] = {
  53.         (char *)_MSG_TRANS_STAT_ERROR,
  54.         (char *)_MSG_TRANS_ERROR_FILEOPEN,
  55.         (char *)_MSG_TRANS_ERROR_FILEREAD,
  56.         (char *)_MSG_TRANS_ERROR_FILEWRITE,
  57.         (char *)_MSG_TRANS_ERROR_NET_UNKNOWN,
  58.         (char *)_MSG_TRANS_ERROR_LOGGEDOUT,
  59.         (char *)_MSG_TRANS_ERROR_NOTFOUND,
  60.         (char *)_MSG_TRANS_ERROR_INVALIDREQUEST,
  61.         (char *)_MSG_TRANS_ERROR_TEASER,
  62.         (char *)_MSG_TRANS_ERROR_BUSY,
  63.         (char *)_MSG_TRANS_ERROR_NOTREQ,
  64.         (char *)_MSG_TRANS_ERROR_NET_TIMEOUT,
  65.         NULL
  66.     };
  67.  
  68.     static char *NetError[] = {
  69.         (char *)_MSG_TRANS_ERROR_NET_TIMEOUT,
  70.         (char *)_MSG_TRANS_ERROR_NET_REFUSED,
  71.         (char *)_MSG_TRANS_ERROR_NET_RESET,
  72.         (char *)_MSG_TRANS_ERROR_NET_PIPE,
  73.         NULL
  74.     };
  75.  
  76.     if (states[0] == (char *)_MSG_TRANS_STAT_PREPARE)
  77.         localize_array(states);
  78.  
  79.     if (errors[0] == (char *)_MSG_TRANS_STAT_ERROR)
  80.         localize_array(errors);
  81.  
  82.     if (NetError[0] == (char *)_MSG_TRANS_ERROR_NET_TIMEOUT)
  83.         localize_array(NetError);
  84.  
  85.     if (sd) {
  86.         if (sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) {
  87.             buf2 = bufd2;
  88.             buf3 = bufd3;
  89.             buf4 = bufd4;
  90.             buf5 = bufd5;
  91.         }
  92.         else {
  93.             buf2 = bufu2;
  94.             buf3 = bufu3;
  95.             buf4 = bufu4;
  96.             buf5 = bufu5;
  97.         }
  98.  
  99.         *array++ = nap_strippath(sd->song->title);
  100.  
  101.         if (sd->state == DLS_WAIT) {
  102.             sprintf(buf5, states[sd->state], sd->ErrorCode);
  103.             *array++ = buf5;
  104.         }
  105.         else if (sd->state != DLS_ERROR)
  106.             *array++ = states[sd->state];
  107.         else {
  108.             switch (sd->error) {
  109.                 case ERROR_FILEOPEN:
  110.                 case ERROR_FILEREAD:
  111.                 case ERROR_FILEWRITE:
  112.                     sprintf(buf5, errors[sd->error], sd->ErrorCode);
  113.                     *array++ = buf5;
  114.                     break;
  115.                 case ERROR_NET:
  116.                     switch (sd->ErrorCode) {
  117.                         case ETIMEDOUT:
  118.                             *array++ = NetError[ERROR_NET_TIMEOUT];
  119.                             break;
  120.                         case ECONNREFUSED:
  121.                             *array++ = NetError[ERROR_NET_REFUSED];
  122.                             break;
  123.                         case ECONNRESET:
  124.                             *array++ = NetError[ERROR_NET_RESET];
  125.                             break;
  126.                         case EPIPE:
  127.                             *array++ = NetError[ERROR_NET_PIPE];
  128.                             break;
  129.                         default:
  130.                             sprintf(buf5, errors[sd->error], sd->ErrorCode);
  131.                             *array++ = buf5;
  132.                     }
  133.                     break;
  134.                 default:
  135.                     *array++ = errors[sd->error];
  136.             }
  137.         }
  138.  
  139.         if (sd->size > 0)
  140.             sprintf(buf2,"\33r%ld / %ld (%d%%)", sd->cur, sd->size, (sd->cur*100+5)/sd->size);
  141.         else sprintf(buf2, "\33r0");    /* Can this happen? */
  142.         *array++ = buf2;
  143.  
  144.         if (sd->cps > 0) {
  145.             if (sd->stalltick < 5 || sd->state >= DLS_FIN) {    /* 5 seconds */
  146.                 sprintf(buf3, "%d", sd->cps);
  147.                 *array++ = buf3;
  148.             }
  149.             else {
  150.                 *array++ = (char *)MSG_TRANS_STAT_STALLED;
  151.             }
  152.             sprintf(buf4, "%ld:%02ld / %ld:%02ld", sd->transtime/60, sd->transtime%60, sd->timeleft/60, sd->timeleft%60);
  153.             *array = buf4;
  154.         }
  155.         else {
  156.             *array++ = "-";
  157.             *array   = "-";
  158.         }
  159.  
  160.     }
  161.     else {
  162.         *array++ = (char *)MSG_LH_FILE;
  163.         *array++ = (char *)MSG_LH_STATE;
  164.         *array++ = (char *)MSG_LH_SIZE;
  165.         *array++ = (char *)MSG_LH_CPS;
  166.         *array =   (char *)MSG_LH_ETIME;
  167.     }
  168.     return 0;
  169. }
  170.  
  171.  
  172. MUI_LIST_DEST(translistdest, songtrans sd)
  173. {
  174.     nap_songfree(sd->song);
  175.     if (sd->fname) free(sd->fname);
  176.     free(sd);
  177.  
  178.     return 0;
  179. }
  180.  
  181.  
  182. ULONG dl_setup(struct IClass *cl, Object *obj, Msg msg)
  183. {
  184.     struct TransferData *data = INST_DATA(cl, obj);
  185.  
  186.     if (!DoSuperMethodA(cl, obj, msg))
  187.         return(FALSE);
  188.  
  189.     DoMethod(_app(obj), MUIM_Application_AddInputHandler, &data->ihnode);
  190. /*    DoMethod(_app(obj), MUIM_Application_AddInputHandler, &data->watchnode);*/
  191.  
  192.     return(TRUE);
  193. }
  194.  
  195.  
  196. ULONG dl_muicleanup(struct IClass *cl, Object *obj, Msg msg)
  197. {
  198.     struct TransferData *data = INST_DATA(cl,obj);
  199.  
  200.     DoMethod(_app(obj), MUIM_Application_RemInputHandler, &data->ihnode);
  201. /*    DoMethod(_app(obj), MUIM_Application_RemInputHandler, &data->watchnode);*/
  202.  
  203.     return(DoSuperMethodA(cl,obj,msg));
  204. }
  205.  
  206.  
  207. void CalculateCps(songtrans sd)
  208. {
  209.     if (sd->cur != sd->oldsize) {
  210.         sd->stalltick = 0;
  211.         sd->oldsize = sd->cur;
  212.     }
  213.     else sd->stalltick++;
  214.  
  215.     sd->transtime = GetDateStamp() - sd->starttime;
  216.     if (sd->transtime == 0) sd->transtime = 1;
  217.     sd->cps = (sd->cur - sd->resumestart) / sd->transtime;
  218.     if (sd->cps > 0)
  219.         sd->timeleft = (sd->size - sd->cur) / sd->cps;
  220.     else sd->timeleft = 0;
  221. }
  222.  
  223.  
  224. void TransferSetError(struct TransferData *data, char *title, char *user, int error)
  225. {
  226.     u_long tmp;
  227.     songtrans sd;
  228.     long i;
  229.  
  230.     for (i=0; ; i++) {
  231.         DoMethod(data->list, MUIM_NList_GetEntry, i, &tmp);
  232.         if (!tmp) return;
  233.         sd = (songtrans)tmp;
  234.         if (strcmp(sd->song->title, title) == 0 && stricmp(sd->song->user, user) == 0 && sd->state < DLS_FIN) break;
  235.     }
  236.  
  237.     if ((sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) && sd->state == DLS_PREP) {
  238.         DoMethod(gui->dwin, DL_COUNTDECREMENT);
  239.     }
  240.  
  241.     sd->state = DLS_ERROR;
  242.     sd->error = error;
  243.  
  244.     if (sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) {
  245.         DoMethod(gui->dwin, DL_RESUME_UPDATE);
  246.         DoMethod(gui->dwin, DL_UPDATE, sd);
  247.     }
  248.     else DoMethod(gui->uwin, UPLOAD_UPDATE, sd);
  249. }
  250.  
  251.  
  252. void TransferInfo(struct TransferData *data)
  253. {
  254.     static char bufd[600], bufu[600];
  255.     char *buf;
  256.     u_long tmp;
  257.     songtrans sd;
  258.  
  259.     GetAttr(MUIA_NList_EntryClick,  data->list, &tmp);
  260.     if (tmp == -1 || tmp == -2) return;
  261.     DoMethod(data->list, MUIM_NList_GetEntry, tmp, &sd);
  262.     if (!sd) return;
  263.  
  264.     if (sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) {
  265.         if (sd->state < DLS_ABORT) set(data->BT_Resume, MUIA_Disabled, TRUE);
  266.         else set(data->BT_Resume, MUIA_Disabled, FALSE);
  267.         buf = bufd;
  268.     }
  269.     else buf = bufu;
  270.  
  271.     if (sd->song->ip == 0) return;
  272.  
  273.     if (sd->host[0] == '\0') {
  274.         sprintf(buf, "%s (%d.%d.%d.%d)", sd->song->user, (sd->song->ip&0xFF000000)>>24, (sd->song->ip&0xFF0000)>>16, (sd->song->ip&0xFF00)>>8, sd->song->ip&0xFF);
  275.     }
  276.     else {
  277.         sprintf(buf, "%s (%s)", sd->song->user, sd->host);
  278.     }
  279.  
  280.     set(data->info, MUIA_Text_Contents, buf);
  281. }
  282.  
  283.  
  284. void TransferAbort(struct TransferData *data)
  285. {
  286.     u_long item;
  287.     songtrans sd;
  288.  
  289.     DoMethod(data->list, MUIM_NList_GetEntry, MUIV_NList_GetEntry_Active, &item);
  290.     if (!item) return;
  291.  
  292.     sd = (songtrans)item;
  293. #ifdef AMSTER_DEBUG
  294. gui_debugf("abort file: %s", sd->song->title);
  295. #endif
  296.  
  297.     if (sd->state >= DLS_FIN) {
  298. #ifdef AMSTER_DEBUG
  299. gui_debug("already wiped");
  300. #endif
  301.         return;
  302.     }
  303.  
  304.     if (sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) {
  305.         if (sd->state == DLS_WAIT) DoMethod(gui->dwin, DL_REMWAITING, sd);
  306.         if (sd->state == DLS_QUEUE) QueueCount--;
  307.     }
  308.  
  309.     if (sd->t) {
  310. #ifdef AMSTER_DEBUG
  311. gui_debug("is in a thread - trying to exit");
  312. #endif
  313.         th_message(sd->t, THC_EXIT, 0);
  314.         Signal(sd->t->task, SIGBREAKF_CTRL_C);
  315.     }
  316.     else {
  317. #ifdef AMSTER_DEBUG
  318. gui_debug("not in a thread");
  319. #endif
  320.         if (sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) {
  321.             if (sd->state != DLS_QUEUE && sd->state != DLS_WAIT) {
  322.                 DoMethod(gui->dwin, DL_COUNTDECREMENT);
  323.             }
  324.         }
  325.         else DoMethod(gui->uwin, UPLOAD_COUNTDECREMENT);
  326.     }
  327.  
  328.     sd->state = DLS_ABORT;
  329.  
  330.     if (sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) {
  331.         set(data->BT_Resume, MUIA_Disabled, FALSE);
  332.         DoMethod(gui->dwin, DL_UPDATE, sd);
  333.         prf_event(PRFE_DLABORT, sd->fname);
  334.     }
  335.     else {
  336.         DoMethod(gui->uwin, UPLOAD_UPDATE, sd);
  337.         prf_event(PRFE_ULABORT, sd->fname);
  338.     }
  339. }
  340.  
  341.  
  342. void TransferCleanup(struct TransferData *data)
  343. {
  344.     u_long item;
  345.     int i=0;
  346.  
  347.     set(data->list, MUIA_NList_Quiet, MUIV_NList_Quiet_Visual);
  348.     while (1) {
  349.         DoMethod(data->list, MUIM_NList_GetEntry, i, &item);
  350.         if (!item) break;
  351.         if (((songtrans)item)->state >= DLS_FIN) DoMethod(data->list, MUIM_NList_Remove, i);
  352.         else i++;
  353.     }
  354.     set(data->list,MUIA_NList_Quiet, MUIV_NList_Quiet_None);
  355. }
  356.  
  357.  
  358. void TransferCleanupSingle(struct TransferData *data, songtrans sd)
  359. {
  360.     long pos;
  361.  
  362.     pos = MUIV_NList_GetPos_Start;
  363.     DoMethod(data->list, MUIM_NList_GetPos, sd, &pos);
  364.     DoMethod(data->list, MUIM_NList_Remove, pos);
  365. }
  366.  
  367.  
  368. void TransferWatcher(struct TransferData *data)
  369. {
  370.     u_long item;
  371.     long i;
  372.     songtrans sd;
  373.  
  374.     for (i=0; ; i++) {
  375.         DoMethod(data->list, MUIM_NList_GetEntry, i, &item);
  376.         if (!item) break;
  377.         sd = (songtrans)item;
  378.         if (sd->state == DLS_PREP) {
  379.             if (GetDateStamp()-sd->reqtime > 120) {    /* We consider this transfer dead/hanging (never started) */
  380.                 sd->state = DLS_ERROR;
  381.                 sd->error = ERROR_TIMEOUT;
  382.                 if (sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) {
  383.                     DoMethod(gui->dwin, DL_COUNTDECREMENT);
  384.                     DoMethod(gui->dwin, DL_UPDATE, sd);
  385.                     DoMethod(gui->dwin, DL_RESUME_UPDATE);
  386.                 }
  387.                 else {
  388.                     DoMethod(gui->uwin, UPLOAD_COUNTDECREMENT);
  389.                     DoMethod(gui->uwin, UPLOAD_UPDATE, sd);
  390.                 }
  391.             }
  392.         }
  393.     }
  394. }
  395.  
  396.  
  397. void TransferHandleError(songtrans sd)
  398. { /* Outside the thread */
  399.     char error[128];
  400.  
  401.     if (sd->ErrorCode == EINTR) return;    /* Aborted with CTRL-C */
  402.  
  403.     if (sd->error != 0) {
  404.         sd->state = DLS_ERROR;
  405.         if (sd->error >= ERROR_FILEOPEN && sd->error <= ERROR_FILEWRITE) {
  406.             Fault(sd->ErrorCode, "", error, 127);
  407.             gui_debugf((char *)MSG_INFO_IOERROR, sd->fname, error);
  408.         }
  409.         else if (sd->error >= ERROR_OUTOFBOUND) sd->error = ERROR_UNKNOWN;
  410.         if (sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) {
  411.             DoMethod(gui->dwin, DL_RESUME_UPDATE);
  412.             prf_event(PRFE_DLERROR, sd->fname);
  413.         }
  414.         else prf_event(PRFE_ULERROR, sd->fname);
  415.     }
  416.     else if (sd->state == DLS_FIN) {
  417.         if (sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) prf_event(PRFE_DLFINISH, sd->fname);
  418.         else prf_event(PRFE_ULFINISH, sd->fname);
  419.     }
  420.  
  421.     if (sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_DOWNLOAD_IN) DoMethod(gui->dwin, DL_UPDATE, sd);
  422.     else DoMethod(gui->uwin, UPLOAD_UPDATE, sd);
  423. }
  424.  
  425.  
  426. /* Thread stuff */
  427.  
  428. BOOL InitTransferThread(thread t, songtrans sd)
  429. {
  430.     struct Library *DOSBase;
  431.     struct Library *SocketBase;
  432.     char *buffer;
  433.     long s;
  434.     long tmp;
  435.     struct hostent *he;
  436.  
  437.     sd->state = DLS_PREP;
  438.  
  439.     sd->nsig = AllocSignal(-1);
  440.     if (sd->nsig == -1) {
  441.         ExitTransferThread(sd, 49);
  442.         return FALSE;
  443.     }
  444.     sd->nsigm = (1L << (sd->nsig));
  445.     sd->msigm = (1L << (t->port->mp_SigBit));
  446.  
  447.     DOSBase = OpenLibrary("dos.library", 0);
  448.     if (!DOSBase) {
  449.         ExitTransferThread(sd, 50);
  450.         return FALSE;
  451.     }
  452.     sd->DOSBase = DOSBase;
  453.  
  454.     SocketBase = OpenLibrary("bsdsocket.library", 0);
  455.     if (!SocketBase) {
  456.         ExitTransferThread(sd, 51);
  457.         return FALSE;
  458.     }
  459.     sd->SocketBase = SocketBase;
  460.  
  461.     SocketBaseTags(SBTM_SETVAL(SBTC_SIGIOMASK), (char *)sd->nsigm, TAG_DONE);
  462.  
  463.     buffer = malloc(8192);
  464.     if (!buffer) {
  465.         ExitTransferThread(sd, 52);
  466.         return FALSE;
  467.     }
  468.     sd->buffer = buffer;
  469.  
  470.     /* Perform DNS-lookup */
  471.     he = gethostbyname(Inet_NtoA(sd->song->ip));
  472.     he = gethostbyaddr(he->h_addr_list[0], he->h_length, AF_INET);
  473.     if (he != 0) strcpy(sd->host, he->h_name);
  474.     else strcpy(sd->host, Inet_NtoA(sd->song->ip));
  475.  
  476.     if (sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_UPLOAD_OUT) {
  477.         s = socket(AF_INET, SOCK_STREAM, 0);
  478.         if (s < 0) {
  479.             ExitTransferThread(sd, 53);
  480.             return FALSE;
  481.         }
  482.         sd->s = s;
  483.     }
  484.     else {
  485.         /* Firewalled transfer - get the already existing socket */
  486.         s = ObtainSocket(sd->s, AF_INET, SOCK_STREAM, 0);
  487.         sd->s = s;
  488.     }
  489.  
  490.     tmp = 1;
  491.     IoctlSocket(s, FIOASYNC, (char *)&tmp);
  492.     IoctlSocket(s, FIONBIO,  (char *)&tmp);
  493.     /* Asynchronous and non-blocking I/O to the socket */
  494.  
  495.     if (sd->type == TYPE_DOWNLOAD_OUT || sd->type == TYPE_UPLOAD_OUT) {
  496.         sd->sin.sin_addr.s_addr = sd->ip;
  497.         sd->sin.sin_port = htons(sd->port);
  498.         sd->sin.sin_family = AF_INET;
  499.         sd->sin.sin_len = sizeof(sd->sin);
  500.  
  501.         tmp = connect(s, (struct sockaddr *)&sd->sin, sizeof(sd->sin));
  502.         if (tmp == -1 && Errno() != EINPROGRESS) {
  503.             sd->ErrorCode = Errno();
  504.             ExitTransferThread(sd, ERROR_NET);
  505.             return FALSE;
  506.         }
  507.         thr_message(t, DLC_STATE, (APTR)DLS_CON);
  508.     }
  509.     else if (sd->type == TYPE_DOWNLOAD_IN) sd->state = DLS_INIT;
  510.  
  511.     return TRUE;
  512. }
  513.  
  514.  
  515. void ExitTransferThread(songtrans sd, int ret)
  516. { /* Inside the thread */
  517.     struct Library *DOSBase=sd->DOSBase;
  518.     struct Library *SocketBase=sd->SocketBase;
  519.  
  520.     if (sd->nsig != -1) FreeSignal(sd->nsig);
  521.     sd->nsig = -1;
  522.  
  523.     if (sd->f) Close(sd->f);
  524.     sd->f = 0;
  525.  
  526.     if (sd->s != -1) CloseSocket(sd->s);
  527.     sd->s = -1;
  528.  
  529.     if (sd->buffer) free(sd->buffer);
  530.     sd->buffer = NULL;
  531.  
  532.     if (SocketBase) CloseLibrary(SocketBase);
  533.     sd->SocketBase = NULL;
  534.  
  535.     if (DOSBase) CloseLibrary(DOSBase);
  536.     sd->DOSBase = NULL;
  537.  
  538.     thr_exit(sd->t, ret);
  539. }
  540.  
  541.  
  542. time_t GetDateStamp(void)
  543. {
  544.     struct DateStamp ds;
  545.     struct DateStamp *rds;
  546.  
  547.     rds = DateStamp(&ds);
  548.     return (rds->ds_Days*24*60*60 + rds->ds_Minute*60 + rds->ds_Tick/TICKS_PER_SECOND);
  549. }
  550.